/*
 * Copyright 2009 Eat Local Food, LLC
 * Copyright (c) 2007 osCommerce (this file was written after
 * code review of osCommerce).
 *
 * This file is part of gwtCommerce.
 *
 * gwtCommerce is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * gwtCommerce is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with gwtCommerce.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.elf.gwt.store.client.components;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.elf.gwt.common.client.access.RequestParameter;
import com.elf.gwt.common.client.callback.TableNavigatorWidgetCallback;
import com.elf.gwt.common.client.components.CommonSimpleComponent;
import com.elf.gwt.common.client.exception.NoResultsFoundException;
import com.elf.gwt.common.client.model.AdvancedSearchModel;
import com.elf.gwt.common.client.model.AdvancedSearchResultsMetaModel;
import com.elf.gwt.common.client.model.ManufacturerModel;
import com.elf.gwt.common.client.model.OrderbyModel;
import com.elf.gwt.common.client.model.ProductModel;
import com.elf.gwt.common.client.utils.CommonUtils;
import com.elf.gwt.common.client.widget.TableNavigatorWidget;
import com.elf.gwt.store.client.GWTCommerceConstants;
import com.elf.gwt.store.client.StoreComponentController;
import com.elf.gwt.store.client.utils.StoreUtils;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.InlineHTML;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;

/**
 *  
 */
public class AdvancedSearchResultsComponent extends ProductsComponent
{
	protected AdvancedSearchResultsMetaModel advancedSearchResultsMetaModel;
	protected List<OrderbyModel> orderbyModels = null;
	protected TableNavigatorWidget navPanelTop = null;
	protected TableNavigatorWidget navPanelBot = null;
	protected AdvancedSearchComponent advancedSearchComponent;

	/**
	 * Constructor
	 */
	public AdvancedSearchResultsComponent(StoreComponentController controller, String stylePrefix)
	{
		super(controller, stylePrefix, null, false);
		advancedSearchComponent = (AdvancedSearchComponent)controller.getComponent("AdvancedSearchComponent");	
		setMaxNumCols(1);
	}

	public boolean updateFromHistoryParameters(String[] params)
	{
		advancedSearchComponent.updateModelFromHistoryParameters(params);
		storeController.getMultipleResultsComponent().addComponent(this);

		//Don't look for new products
		CommonSimpleComponent alwaysAskComponent = controller.getComponent("NewProductsComponent", false);
		if (alwaysAskComponent != null) storeController.getMultipleResultsComponent().removeComponent(alwaysAskComponent);

		return super.updateFromHistoryParameters(params);
	}

	/**
	 * add the additional request parameters for searching.
	 */
	public void additionalRequestParameters()
	{
		super.additionalRequestParameters();
		AdvancedSearchModel model = advancedSearchComponent.getAdvancedSearchModel();
		addRequestParameter(new RequestParameter("inc_subcat", model.isIncludeSubCategories()));
		addRequestParameter(new RequestParameter("pfrom", model.getPriceFrom()));
		addRequestParameter(new RequestParameter("pto", model.getPriceTo()));
		addRequestParameter(new RequestParameter("dfrom", model.getDateFrom()));
		addRequestParameter(new RequestParameter("dto", model.getDateTo()));
		addRequestParameter(new RequestParameter("keywords", model.getKeywords()));
		addRequestParameter(new RequestParameter("desc_search", model.isDescriptionSearch()));
		addRequestParameter(new RequestParameter("offset", model.getOffset()));
		addRequestParameter(new RequestParameter("orderby", model.getOrderby()));

		if (model.isSearchSpecials()) 
			addRequestParameter(new RequestParameter("searchSpecials", 1));
		else
			addRequestParameter(new RequestParameter("searchSpecials", 0));
	}

	public void build(Throwable exception)
	{
		GWT.log(getHandle(), exception);
		try {
			throw exception;
		}
		catch (NoResultsFoundException ex)
		{
			try {
				productModels.clear();
				buildFromModel();
			}
			catch (Exception ex1)
			{
				GWT.log(getHandle() + ".buildFromModel()", ex1);
				panel.setText(1, 0, ex1.toString());
			}
		}
		catch (Throwable ex) {
			panel.setText(1, 0, exception.toString());
		}
		onBuilt();
	}

	protected void buildMetaModel(JSONObject jsonObject) throws Exception
	{
		super.buildMetaModel(jsonObject);
		advancedSearchResultsMetaModel = new AdvancedSearchResultsMetaModel(jsonObject);
	}

	public void buildFromModel() throws Exception
	{
		GWTCommerceConstants constants = storeController.getStoreConstants();
		VerticalPanel bodyPanel = new VerticalPanel();
		bodyPanel.setWidth("100%");
		bodyPanel.addStyleName(getHandle() + "BodyPanel");
		panel.setWidget(1, 0, bodyPanel);

		//Order By
		if (orderbyModels == null)
		{
			orderbyModels = new ArrayList<OrderbyModel>();

			String orderbyDelimiter = " " + constants.AdvancedSearchResultsComponentOrderbyDelimiter() + " ";
			String ascending = orderbyDelimiter + constants.AdvancedSearchResultsComponentOrderbyAscending();
			String descending = orderbyDelimiter + constants.AdvancedSearchResultsComponentOrderbyDescending();

			if (advancedSearchResultsMetaModel.getDisplayName() > 0)
			{
				orderbyModels.add(new OrderbyModel(constants.AdvancedSearchResultsComponentOrderbyName() + ascending, "pd.products_name"));
				orderbyModels.add(new OrderbyModel(constants.AdvancedSearchResultsComponentOrderbyName() + descending, "pd.products_name desc"));
			}
			if (advancedSearchResultsMetaModel.getDisplayModel() > 0)
			{
				orderbyModels.add(new OrderbyModel(constants.AdvancedSearchResultsComponentOrderbyModel() + ascending, "p.products_model"));
				orderbyModels.add(new OrderbyModel(constants.AdvancedSearchResultsComponentOrderbyModel() + descending, "p.products_model desc"));
			}
			if (advancedSearchResultsMetaModel.getDisplayManufacturer() > 0)
			{
				orderbyModels.add(new OrderbyModel(constants.AdvancedSearchResultsComponentOrderbyManufacturer() + ascending, "m.manufacturers_name"));
				orderbyModels.add(new OrderbyModel(constants.AdvancedSearchResultsComponentOrderbyManufacturer() + descending, "m.manufacturers_name desc"));
			}
			if (advancedSearchResultsMetaModel.getDisplayPrice() > 0)
			{
				orderbyModels.add(new OrderbyModel(constants.AdvancedSearchResultsComponentOrderbyPrice() + ascending, "p.products_price"));
				orderbyModels.add(new OrderbyModel(constants.AdvancedSearchResultsComponentOrderbyPrice() + descending, "p.products_price desc"));
			}
			if (advancedSearchResultsMetaModel.getDisplayQuantity() > 0)
			{
				orderbyModels.add(new OrderbyModel(constants.AdvancedSearchResultsComponentOrderbyQuantity() + ascending, "p.products_quantity"));
				orderbyModels.add(new OrderbyModel(constants.AdvancedSearchResultsComponentOrderbyQuantity() + descending, "p.products_quantity desc"));
			}
			if (advancedSearchResultsMetaModel.getDisplayWeight() > 0)
			{
				orderbyModels.add(new OrderbyModel(constants.AdvancedSearchResultsComponentOrderbyWeight() + ascending, "p.products_weight"));
				orderbyModels.add(new OrderbyModel(constants.AdvancedSearchResultsComponentOrderbyWeight() + descending, "p.products_weight desc"));
			}
			orderbyModels.add(new OrderbyModel(constants.AdvancedSearchResultsComponentOrderbyDateAdded() + ascending, "p.products_date_added"));
			orderbyModels.add(new OrderbyModel(constants.AdvancedSearchResultsComponentOrderbyDateAdded() + descending, "p.products_date_added desc"));
		}

		AdvancedSearchModel asmodel = advancedSearchComponent.getAdvancedSearchModel();
		String orderby = asmodel.getOrderby();

		if (orderby != null && orderby.length() > 0)
		{
			Iterator<OrderbyModel> iter = orderbyModels.iterator();
			while (iter.hasNext())
			{
				OrderbyModel orderbyModel = iter.next();
				if (orderby.equals(orderbyModel.getOrderclause())) {
					orderbyModel.setSelected(true);
				}
				else {
					orderbyModel.setSelected(false);
				}
			}
		}

		//Top Navigation
		if (productMetaModel.getPrevNextBarLocation() == 1 || productMetaModel.getPrevNextBarLocation() == 3)
		{
			if (navPanelTop == null)
			{
				navPanelTop = new TableNavigatorWidget(constants.AdvancedSearchResultsComponentProducts(), productMetaModel.getTotalRows(), 
						productMetaModel.getMaxRows(), productMetaModel.getRows(), productMetaModel.getOffset(), 
						productMetaModel.getPageLinksMax(), orderbyModels,
						controller.getCommonConstants(), StoreComponentController.languagesComponent.getLanguageModel().getCode(), new ASTableNavigatorCallback(),
						CommonUtils.getImageDirectory());
			}
			else
			{
				navPanelTop.refresh(productMetaModel.getTotalRows(), productMetaModel.getMaxRows(), productMetaModel.getRows(), productMetaModel.getOffset());
			}

			bodyPanel.add(navPanelTop);
			navPanelTop.setStyleName(getHandle() + "NavigationPanel");
		}
		//Table
		int sz = productModels.size();
		int colnum = 2;
		if (advancedSearchResultsMetaModel.getDisplayImage() > 0) colnum++;
		Grid bodyTable = new Grid(sz+1, colnum);
		bodyTable.setWidth("100%");
		bodyTable.setStyleName(getHandle() + "BodyTable");
		CellFormatter cf = bodyTable.getCellFormatter();
		bodyPanel.add(bodyTable);

		InlineLabel label1 = null;
		InlineLabel label2 = new InlineLabel(constants.AdvancedSearchResultsComponentProductTitle());
		InlineLabel label3 = new InlineLabel(constants.AdvancedSearchResultsComponentButtonsTitle());

		if (advancedSearchResultsMetaModel.getDisplayImage() > 0) {
			label1 = new InlineLabel(constants.AdvancedSearchResultsComponentImageTitle());
			bodyTable.setWidget(0, 0, label1);
			bodyTable.setWidget(0, 1, label2);
			bodyTable.setWidget(0, 2, label3);
			cf.setHorizontalAlignment(0, 0, HasHorizontalAlignment.ALIGN_CENTER);
			cf.setHorizontalAlignment(0, 1, HasHorizontalAlignment.ALIGN_CENTER);
			cf.setHorizontalAlignment(0, 2, HasHorizontalAlignment.ALIGN_CENTER);
			cf.setStyleName(0, 0, getHandle() + "BodyTableTitle");
			cf.setStyleName(0, 1, getHandle() + "BodyTableTitle");
			cf.setStyleName(0, 2, getHandle() + "BodyTableTitle");
			cf.setWidth(0, 1, "100%");
		}
		else
		{
			bodyTable.setWidget(0, 0, label2);
			bodyTable.setWidget(0, 1, label3);
			cf.setHorizontalAlignment(0, 0, HasHorizontalAlignment.ALIGN_CENTER);
			cf.setHorizontalAlignment(0, 1, HasHorizontalAlignment.ALIGN_CENTER);
			cf.setStyleName(0, 0, getHandle() + "BodyTableTitle");
			cf.setStyleName(0, 1, getHandle() + "BodyTableTitle");
			cf.setWidth(0, 0, "100%");
		}
		//Bottom Navigation
		if (productMetaModel.getPrevNextBarLocation() == 2 || productMetaModel.getPrevNextBarLocation() == 3)
		{
			if (navPanelBot == null)
			{
				navPanelBot = new TableNavigatorWidget(constants.AdvancedSearchResultsComponentProducts(), productMetaModel.getTotalRows(), 
						productMetaModel.getMaxRows(), productMetaModel.getRows(), productMetaModel.getOffset(), 
						productMetaModel.getPageLinksMax(), orderbyModels,
						controller.getCommonConstants(), StoreComponentController.languagesComponent.getLanguageModel().getCode(), new ASTableNavigatorCallback(),
						CommonUtils.getImageDirectory());
			}
			else
			{
				navPanelBot.refresh(productMetaModel.getTotalRows(), productMetaModel.getMaxRows(), productMetaModel.getRows(), productMetaModel.getOffset());
			}

			bodyPanel.add(navPanelBot);
			navPanelBot.setStyleName(getHandle() + "NavigationPanel");
		}

		String delimiter = constants.AdvancedSearchResultsComponentDelimiter();

		for (int i = 0; i < sz; i++)
		{
			ProductModel productModel = productModels.get(i);

			VerticalPanel vpanel1 = null;
			VerticalPanel vpanel2 = new VerticalPanel();
			VerticalPanel vpanel3 = new VerticalPanel();

			if (advancedSearchResultsMetaModel.getDisplayImage() > 0)
			{
				vpanel1 = new VerticalPanel();
				Image image = new Image();
				image.setStyleName("ComponentImage");
				image.addStyleName(getHandle() + "Image");
				image.addStyleName("ComponentLink");
				image.addStyleName("index:" + i);
				image.setUrl(StoreUtils.getImageProductsDirectory() + productModel.getImage());
				image.addClickHandler(productClickHandler);
				String[] imageSize = productModel.getImageSize();
				image.setSize(imageSize[0], imageSize[1]);
				image.setTitle(productModel.getName());
				vpanel1.add(image);
			}
			if (advancedSearchResultsMetaModel.getDisplayName() > 0)
			{
				String name = productModel.getName();
				InlineHTML nameLabel = new InlineHTML("<strong>" + constants.AdvancedSearchResultsComponentName() + delimiter + "</strong>" + " " + name);
				nameLabel.addStyleName("ComponentLink");
				nameLabel.addStyleName("index:" + i);
				nameLabel.addClickHandler(productClickHandler);
				vpanel2.add(nameLabel);
			}
			if (advancedSearchResultsMetaModel.getDisplayModel() > 0)
			{
				String model = productModel.getModel();
				vpanel2.add(new InlineHTML("<strong>" + constants.AdvancedSearchResultsComponentModel() + delimiter + "</strong>" + " " + model));
			}
			if (advancedSearchResultsMetaModel.getDisplayManufacturer() > 0)
			{
				int manufacturerId = productModel.getManufacturerId();
				if (manufacturerId > 0)
				{
					ManufacturerModel mmodel = StoreComponentController.manufacturersComponent.getManufacturerModelById(manufacturerId);
					vpanel2.add(new InlineHTML("<strong>" + constants.AdvancedSearchResultsComponentManufacturer() + delimiter + "</strong>" + " " + mmodel.getName()));
				}
			}
			if (advancedSearchResultsMetaModel.getDisplayPrice() > 0)
			{
				String priceOut = CommonUtils.productPriceDisplay(StoreComponentController.currenciesComponent.getCurrencyModel(), productModel.getPrice(), 
						productModel.getDiscountPrice(), productModel.getSpecialPrice());
				if (productModel.getWeight() < 0.00001 && !productModel.isVirtual()) priceOut += "<br/><strong>Shipping" + delimiter + "</strong> Free!";
				vpanel2.add(new InlineHTML("<strong>" + constants.AdvancedSearchResultsComponentPrice() + delimiter + "</strong>" + " " + priceOut));

			}
			if (advancedSearchResultsMetaModel.getDisplayQuantity() > 0)
			{
				int quantity = productModel.getInventoryQuantity();
				vpanel2.add(new InlineHTML("<strong>" + constants.AdvancedSearchResultsComponentQuantity() + delimiter + "</strong>" + " " + String.valueOf(quantity)));
			}
			if (advancedSearchResultsMetaModel.getDisplayWeight() > 0)
			{
				double weight = productModel.getWeight();
				vpanel2.add(new InlineHTML("<strong>" + constants.AdvancedSearchResultsComponentWeight() + delimiter + "</strong>" + " " + String.valueOf(weight)));
			}

			vpanel2.add(new InlineHTML("<strong>" + constants.AdvancedSearchResultsComponentDateAdded() + delimiter + "</strong>" + " "
					+ DateTimeFormat.getFormat(DateTimeFormat.PredefinedFormat.DATE_MEDIUM).format(productModel.getDateAdded())));

			//Buttons
			if (advancedSearchResultsMetaModel.getDisplayBuyNow() > 0)
			{
				Button buynowButton = new Button(controller.getCommonConstants().BuyNow(), cartClickHandler);
				buynowButton.addStyleName(getHandle() + "BodyTableButton");
				buynowButton.addStyleName("index:" + i);
				vpanel3.add(buynowButton);
				vpanel3.setCellHorizontalAlignment(buynowButton, HasHorizontalAlignment.ALIGN_CENTER);
			}
			Button detailsButton = new Button(controller.getCommonConstants().Details(), productClickHandler);
			detailsButton.addStyleName(getHandle() + "BodyTableButton");
			detailsButton.addStyleName("index:" + i);
			vpanel3.add(detailsButton);
			vpanel3.setCellHorizontalAlignment(detailsButton, HasHorizontalAlignment.ALIGN_CENTER);


			if (advancedSearchResultsMetaModel.getDisplayImage() > 0) {
				cf.setHorizontalAlignment(i+1, 0, HasHorizontalAlignment.ALIGN_CENTER);
				cf.setHorizontalAlignment(i+1, 2, HasHorizontalAlignment.ALIGN_CENTER);
				cf.setStyleName(i+1, 0, getHandle() + "BodyTableCell");
				cf.setStyleName(i+1, 1, getHandle() + "BodyTableCell");
				cf.setStyleName(i+1, 2, getHandle() + "BodyTableCell");
				cf.addStyleName(i+1, 0, getHandle() + "BodyTableImage");
				cf.addStyleName(i+1, 1, getHandle() + "BodyTableData");
				cf.addStyleName(i+1, 2, getHandle() + "BodyTableButtons");
				bodyTable.setWidget(i+1, 0, vpanel1);
				bodyTable.setWidget(i+1, 1, vpanel2);
				bodyTable.setWidget(i+1, 2, vpanel3);
				cf.setWidth(i+1, 1, "100%");
			}
			else
			{
				cf.setHorizontalAlignment(i+1, 1, HasHorizontalAlignment.ALIGN_CENTER);
				cf.setStyleName(i+1, 0, getHandle() + "BodyTableCell");
				cf.setStyleName(i+1, 1, getHandle() + "BodyTableCell");
				cf.addStyleName(i+1, 0, getHandle() + "BodyTableData");
				cf.addStyleName(i+1, 1, getHandle() + "BodyTableButtons");
				bodyTable.setWidget(i+1, 0, vpanel2);
				bodyTable.setWidget(i+1, 1, vpanel3);
				cf.setWidth(i+1, 0, "100%");
			}
		}

		onBuilt();
	}

	protected ClickHandler productClickHandler = new ClickHandler() {
		public void onClick(ClickEvent event) {
			Widget source = (Widget)event.getSource();
			String stylenames = source.getStyleName();
			int loc = stylenames.indexOf("index:");
			stylenames = stylenames.substring(loc+6);
			loc = stylenames.indexOf(" ");
			if (loc > -1) stylenames = stylenames.substring(0, loc);
			int index = Integer.parseInt(stylenames);
			ProductModel productModel = getProductModel(index);
			int mid = 0;
			if (!isClearManufacturerId()) mid = StoreComponentController.manufacturersComponent.getManufacturerModel().getId();
			onSelection("ProductComponent--" + productModel.getId() + "--"
					+ productModel.getCategoryId() + "--" 
					+ mid);
		}
	};

	protected ClickHandler cartClickHandler = new ClickHandler() {
		public void onClick(ClickEvent event) {
			Widget source = (Widget)event.getSource();
			String stylenames = source.getStyleName();
			int loc = stylenames.indexOf("index:");
			stylenames = stylenames.substring(loc+6);
			loc = stylenames.indexOf(" ");
			if (loc > -1) stylenames = stylenames.substring(0, loc);
			int index = Integer.parseInt(stylenames);
			onCartSelection(index);
		}
	};

	public class ASTableNavigatorCallback implements TableNavigatorWidgetCallback
	{
		public void onSelection(int offset)
		{
			AdvancedSearchModel asmodel = advancedSearchComponent.getAdvancedSearchModel();
			asmodel.setOffset(offset);
			thisComponent.onSelection(getHistory());
		}

		public void onOrderby(String orderby)
		{
			AdvancedSearchModel asmodel = advancedSearchComponent.getAdvancedSearchModel();
			asmodel.setOffset(0);
			asmodel.setOrderby(orderby);
			thisComponent.onSelection(getHistory());
		}
	}
	
	public String getHistory()
	{
		String history = "AdvancedSearchResultsComponent--";

		AdvancedSearchModel advancedSearchModel = advancedSearchComponent.getAdvancedSearchModel();

		history += StoreComponentController.categoriesComponent.getCategoryModel().getId() + "--";
		history += StoreComponentController.manufacturersComponent.getManufacturerModel().getId() + "--";
		history += advancedSearchModel.isDescriptionSearch() + "--";
		history += advancedSearchModel.isIncludeSubCategories() + "--";
		history += advancedSearchModel.isSearchSpecials() + "--";
		history += advancedSearchModel.getPriceFrom() + "--";
		history += advancedSearchModel.getPriceTo() + "--";

		if (advancedSearchModel.getDateFrom() == null)
			history += "*--";
		else
			history += advancedSearchModel.getDateFrom() + "--";

		if (advancedSearchModel.getDateTo() == null)
			history += "*--";
		else
			history += advancedSearchModel.getDateTo() + "--";

		history += advancedSearchModel.getOffset() + "--";
		history += advancedSearchModel.getOrderby() + "--";

		String keywords = advancedSearchModel.getKeywords();
		if (keywords == null || keywords.length() == 0) keywords = "*";
		history += keywords;

		return history;
	}
}
